#include "render_batch.h"

using namespace cli_parse;

/*
int
RenderBatch::operator < (const RenderBatch& rhs) const
{
  eTB_Printf ("Sort Me...\n");

  if (tex_id < rhs.tex_id)
      return 1;

  return 0;
}
*/

/*
RenderBatch::RenderBatch (const RenderBatch& batch)
{
  eTB_Printf ("Crud 1!\n");
  *this = batch;
}
*/

/*
RenderBatch&
RenderBatch::operator= (const RenderBatch& rhs)
{
  eTB_Printf ("Crud 2!\n");
  
  texture    = rhs.texture;
  vcache     = rhs.vcache;
  icache     = rhs.icache;

  tex_id     = rhs.tex_id;
  tex_frames = rhs.tex_frames;
  type       = rhs.type;

  xanim      = rhs.xanim;
  yanim      = rhs.yanim;

  rgbgen     = rhs.rgbgen;

  animated   = rhs.animated;

  generated  = rhs.generated;

  surface    = rhs.surface;
  sector     = rhs.sector;

  primitive_type = rhs.primitive_type;
  

  return *this;
}
*/

cli_parse::RenderBatch*
cli_parse::RenderBatch::Combine (const RenderBatch& input, bool connected)
{
  #ifdef COMBINE_TRIANGLE_STRIPS
      // Add 1 vertex to make a degenerate triangle, so that strips
      //  can be combined.
      bool need_degenerate  = (! connected) && (input.primitive_type == e3dRenderStates::TriangleStrip);
      bool added_degenerate = false;

      if (! icache->GetSize ())
        need_degenerate = false;

      // Cannot combine batches unless the tex and vcaches are shared.
      if (input.tex_id == tex_id &&
          input.vcache == vcache) {
        int first_new_vtx        = 0;
        int num_degenerate_verts = 4;

        size_t old_size = icache->GetSize ();
        size_t new_size = icache->GetSize () + input.icache->GetSize ();
          
        if (new_size != icache->GetSize ()) {
          if (need_degenerate) {
            size_t num_verts = ((input.icache->GetSize ()));

            // Odd numbered triangle strips need an extra vert.
            if (num_verts % 2)
              num_degenerate_verts++;

            new_size += num_degenerate_verts;
          }
        }

        if (connected && input.primitive_type == e3dRenderStates::TriangleStrip) {
          new_size      -= 1;
          first_new_vtx += 1;
        }

        e3dIndexCache* pICacheOut = icache;

        if (! generated)
          pICacheOut = cli_parse::states->render_context->CreateIndexCache ();

        pICacheOut->Resize (new_size);

        for (unsigned int i = 0; i < new_size; i++) {
          // Insert the original triangles first
          if (i < old_size) {
            if (! generated)
              pICacheOut->SetIndex (i, icache->GetIndex (i));
          }
            
          // Insert the new triangles (including degenerate triangles) after
          // all original triangles have been inserted.
          else {
            // Insert degenerate triangles
            if (need_degenerate && (! added_degenerate)) {
              e3dIndex last_idx      = icache->GetIndex       (i - 1);
              e3dIndex next_idx      = input.icache->GetIndex (i - old_size +     first_new_vtx);
              e3dIndex next_next_idx = input.icache->GetIndex (i - old_size + 1 + first_new_vtx);

              AddDegenerate (pICacheOut, i, num_degenerate_verts >= 5, last_idx, next_idx, next_next_idx);

              i += (num_degenerate_verts - 1);

              added_degenerate = true;
            } else {
              if (need_degenerate)
                pICacheOut->SetIndex (i, input.icache->GetIndex (i - old_size - num_degenerate_verts + first_new_vtx));
              else
                pICacheOut->SetIndex (i, input.icache->GetIndex (i - old_size + first_new_vtx));
            }
          }
        }

        if (! generated) {
          RenderBatch* batch = new RenderBatch (vcache, pICacheOut);
          batch->generated   = true;
          return batch;
        } else {
          return this;
        }
      }
  #else
      // Cannot combine batches unless the tex and vcaches are shared.
      if (input.tex_id == tex_id &&
          input.vcache == vcache) {
        if (! generated) {
          int new_size = icache->GetSize () + input.icache->GetSize ();
          e3dIndexCache*  icache_ = cli_parse::states->render_context->CreateIndexCache ();

          icache_->Resize (new_size);

          for (int i = 0; i < new_size; i++) {
            if (i < icache->GetSize ()) {
              icache_->SetIndex (i, icache->GetIndex (i));
            } else {
              icache_->SetIndex (i, input.icache->GetIndex (i - icache->GetSize ()));
            }
          }

          RenderBatch* batch = new RenderBatch (vcache, icache_);
          batch->generated = true;
          return batch;
        } else {
          int idx_start = icache->GetSize ();
          icache->Resize (idx_start + input.icache->GetSize ());

          for (int i = 0; i < input.icache->GetSize (); i++) {
            icache->SetIndex (idx_start + i, input.icache->GetIndex (i));
          }

          return this;
        }
      }
  #endif

      return NULL;

}


BatchProcessor cli_parse::batch_processor; 

#include "../states.h"
#include "../console.h" // eTB_Printf

void
cli_parse::BatchProcessor::Reset (void)
{
  num_triangles_ = 0;
  num_batches_   = 0;
}

void
cli_parse::BatchProcessor::Draw ( e3dVertexCache*         vcache,
                                  cli_parse::RenderBatch* batch )
{
////  if (batch->primitive_type != e3dRenderStates::Triangles)
////    eTB_Printf ("Non-Triangle Rendered...\n");

  vcache->DrawIndexed ( batch->primitive_type,
                          batch->icache,
                            0,
                              (unsigned int)batch->icache->GetSize () );

  num_triangles_ += (unsigned int)batch->icache->GetSize () / 3;
  num_batches_   += 1;
}

int
cli_parse::BatchProcessor::GetNumTriangles (void)
{
  return num_triangles_;
}

int
cli_parse::BatchProcessor::GetNumBatches (void)
{
  return num_batches_;
}
